#include "src/server/blog_server.h"

#include <string_view>

#include "src/base/fio66_logger.h"
#include "src/base/utils.h"
#include "src/net/http/http_request.h"
#include "src/net/http/http_response.h"

namespace fio66 {

namespace detail {
std::string_view GetStatusString(fio66::net::HttpStatusCode code) {
  switch (code) {
    case fio66::net::HttpStatusCode::k200OK:
      return "OK";
    case fio66::net::HttpStatusCode::k301MovedPermanently:
      return "MovedPermanently";
    case fio66::net::HttpStatusCode::k400BadRequest:
      return "BadRequest";
    case fio66::net::HttpStatusCode::k404NotFound:
      return "404NotFound";
    default:
      return "Unknow Status";
  }
}

// 高性能URL解码（错误安全版）
std::string UrlDecode(std::string_view encoded) {
    std::string decoded;
    decoded.reserve(encoded.size());
    
    // 十六进制字符转换函数
    auto hex_value = [](char c) -> int {
        if (c >= '0' && c <= '9') return c - '0';
        if (c >= 'a' && c <= 'f') return 10 + c - 'a';
        if (c >= 'A' && c <= 'F') return 10 + c - 'A';
        return -1; // 无效字符
    };
    
    for (size_t i = 0; i < encoded.size(); ++i) {
        if (encoded[i] == '%') {
            // 检查是否缺少两个后续字符
            if (i + 2 >= encoded.size()) {
                return "";
            }
            
            // 检查两个字符是否都是有效的十六进制数字
            int high_nibble = hex_value(encoded[i + 1]);
            int low_nibble = hex_value(encoded[i + 2]);
            
            if (high_nibble < 0 || low_nibble < 0) {
                return "";
            }
            
            // 组合成完整的字节
            char byte = static_cast<char>((high_nibble << 4) | low_nibble);
            decoded += byte;
            i += 2; // 跳过已处理的两位十六进制数字
        }
        else if (encoded[i] == '+') {
            decoded += ' ';
        }
        else {
            decoded += encoded[i];
        }
    }
    
    return decoded;
}
}  // namespace detail

BlogServer::BlogServer(BlogServerConfig config, net::EventLoop* event_loop) : config_(config), cacher_(event_loop, config.uri_path), http_server_(event_loop, net::InetAddress(config_.port), std::string_view("blog_server")) {
  http_server_.SetThreadNum(config_.thread_num);
  http_server_.SetHttpCallback(std::bind(&BlogServer::OnConnect, this, std::placeholders::_1, std::placeholders::_2));
}

bool BlogServer::Start() {
  cacher_.Start();
  http_server_.Start();
  return true;
}

void BlogServer::OnConnect(const net::HttpRequest& request, net::HttpResponse* response) {
  LOGD << "Get request, version:" << request.VersionString() << ", method:" << request.MethodString() << ", path:" << request.Path();

  if (!CheckRequestValid(request)) {
    SendHttpMsg(response, fio66::net::HttpStatusCode::k400BadRequest);
    return;
  }
  
  auto file_info = TryToFindFileConeten(request);
  if (file_info) {
    response->SetContentType(file_info->file_type);
    SendHttpMsg(response, fio66::net::HttpStatusCode::k200OK, file_info->file_content);
  } else {
    SendHttpMsg(response, fio66::net::HttpStatusCode::k404NotFound);
  }
}

bool BlogServer::CheckRequestValid(const net::HttpRequest& request) {
  if (fio66::net::HttpMethod::kGet != request.Method()) {
    return false;
  }
  return true;
}

void BlogServer::SendHttpMsg(net::HttpResponse* response, const fio66::net::HttpStatusCode code, std::string_view body) {
  response->SetStatusCode(code);
  response->SetStatusMessage(detail::GetStatusString(code));
  if (!body.empty()) {
    response->SetBody(body);
  } else {
    response->SetCloseConnection(true);
  }
}

std::shared_ptr<BlogCacher::FileInfo> BlogServer::TryToFindFileConeten(const net::HttpRequest& request) {
  std::filesystem::path path = detail::UrlDecode(request.Path());
  auto file_info = cacher_.GetFileInfo(path);
  if(!file_info && !path.has_extension()) {
    file_info = cacher_.GetFileInfo(path / "index.html");
    if(!file_info) {
      file_info = cacher_.GetFileInfo(path.replace_extension(".html"));
    }
  }
  return file_info;
}

}  // namespace fio66
